﻿using System;
using System.Text;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using FamilyTreeProject.Framework.Entities;
using FamilyTreeProject.ComponentModel;
using FamilyTreeProject.Data.Repositories;
using FamilyTreeProject.Tests.Repositories;
using FamilyTreeProject.Framework;
using FamilyTreeProject.Framework.Enums;
using FamilyTreeProject.Framework.Structures;
using FamilyTreeProject.Library.Tests.Common;

namespace FamilyTreeProject.Library.Tests
{
    /// <summary>
    /// Summary description for IndividualTests
    /// </summary>
    [TestClass]
    public class IndividualTests
    {
        public IndividualTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        #region Private Members

        private TestContext testContextInstance;

        #endregion

        #region Public Properties

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #endregion

        #region Additional test attributes

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext) 
        {
            Container.RegisterService<IFamilyTreeRepository, MockFamilyTreeRepository>();
        }

        [ClassCleanup()]
        public static void MyClassCleanup() { }

        [TestInitialize()]
        public void MyTestInitialize() 
        {
        }
        

        [TestCleanup()]
         public void MyTestCleanup() { }
        
        #endregion

        #region Private Methods

        private void CheckIndividualChildCollections(IIndividual individual, string ignore)
        {
            //Individual Child Collections
            if (! ignore.Contains("Changed"))
                Assert.IsTrue(individual.Changed.Count == 0, "Changed Count should be 0");
            if (! ignore.Contains("Children"))
                Assert.IsTrue(individual.Children.Count == 0, "Children Count should be 0");
            Assert.IsTrue(individual.Enrichment.Count == 0, "Enrichment Count should be 0");
            Assert.IsTrue(individual.Events.Count == 0, "Events Count should be 0");
            Assert.IsTrue(individual.Evidence.Count == 0, "Enrichment Count should be 0");
            Assert.IsTrue(individual.PersonalInfo.Count == 0, "PersonalInfo Count should be 0");
            if (! ignore.Contains("Spouses"))
                Assert.IsTrue(individual.Spouses.Count == 0, "Spouses Count should be 0");
        }

        private void CheckUnsetIndividualParents(IIndividual individual)
        {
            Assert.IsNull(individual.Father, "Unset Father should be null");
            Assert.IsNull(individual.Mother, "Unset Mother should be null");
        }

        private void CheckUnsetIndividualProperties(IIndividual individual)
        {
             //Individual Properties
            Assert.AreEqual<DeathStatus>(Utility.INDIVIDUAL_UNSET_DeathStatus, individual.DeathStatus, "Unset Death Status should be Unknown");
            Assert.AreEqual<string>(String.Empty, individual.DisplayName, String.Concat("Unset Display Name should be an Empty String: DisplayName is: <", individual.DisplayName, ">"));
            Assert.AreEqual<Name>(new Name(), individual.Name, "Unset Name should be 'Empty'");
            Assert.AreEqual<Sex>(Utility.INDIVIDUAL_UNSET_Sex, individual.Sex, "Unset Sex should be Unknown");
       }

        private void CheckSetIndividualProperties(IIndividual individual)
        {
            //Individual Properties
            Assert.AreEqual<DeathStatus>(Utility.INDIVIDUAL_DeathStatus, individual.DeathStatus, "Death Status should be Living");
            Assert.AreEqual<string>(Utility.INDIVIDUAL_Name.ToString(NameFormat.FirstLastLong), individual.DisplayName, String.Concat("Display Name should be Mr. John Doe: DisplayName is: <", individual.DisplayName, ">"));
            Assert.AreEqual<Name>(Utility.INDIVIDUAL_Name, individual.Name, "Name should be 'Mr. John Doe'");
            Assert.AreEqual<Sex>(Utility.INDIVIDUAL_Sex, individual.Sex, "Sex should be Male");
        }

        #endregion

        #region Tests

        [TestMethod]
        [Description("This test Creates a new Individual with No initial ID")]
        [Owner("Charles Nurse")]
        public void CreateIndividualWithNoID()
        {
            IIndividual individual = FamilyTree.CreateIndividual();

            //Individual properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_UNSET_Id, individual.Id, "Unset ID should be -1");
            CheckUnsetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            //Individual Collections
            CheckIndividualChildCollections(individual, String.Empty);
        }

        [TestMethod]
        [Description("This test Creates a new Individual with an initial ID")]
        [Owner("Charles Nurse")]
        public void CreateIndividualWithID()
        {
            IIndividual individual = FamilyTree.CreateIndividual(Utility.INDIVIDUAL_NEW_Id);

            //Object properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_NEW_Id, individual.Id, "Set ID should be 1");
            CheckUnsetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            //Individual Collections
            CheckIndividualChildCollections(individual, String.Empty);
        }

        [TestMethod]
        [Description("This test Gets an Individual which has no child collections and no Father/Mother.")]
        [Owner("Charles Nurse")]
        public void GetIndividualWithID()
        {
            IIndividual individual = FamilyTree.GetIndividual(Utility.INDIVIDUAL_Id);

            //Object properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_Id, individual.Id, "Set ID should be 3");
            CheckSetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            //Check Child Collections are empty
            CheckIndividualChildCollections(individual, String.Empty);
        }

        [TestMethod]
        [Description("This test Gets an Individual which does not exist.")]
        [Owner("Charles Nurse")]
        public void GetIndividualWithIDNotExists()
        {
            IIndividual individual = FamilyTree.GetIndividual(Utility.INDIVIDUAL_NOTEXISTS_Id);

            Assert.IsNull(individual, "An Individual that does not exist should be returned as a null value");
        }

        [TestMethod]
        [Description("This test Gets an Individual that has children.")]
        [Owner("Charles Nurse")]
        public void GetIndividualWithChildren()
        {
            IIndividual individual = FamilyTree.GetIndividual(Utility.INDIVIDUAL_CHILDREN_Id);

            //Object properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_CHILDREN_Id, individual.Id, "Set ID should be 4");
            CheckSetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            Assert.IsTrue(individual.Children.Count == 2, "Children Count should be 2");

            //Child One properties
            IIndividual childOne = individual.Children[0];
            Assert.AreEqual<int>(Utility.CHILD_ONE_Id, childOne.Id, "Child One ID should be 5");
            Assert.AreEqual<DeathStatus>(Utility.CHILD_ONE_DeathStatus, childOne.DeathStatus, "Death Status should be Dead");
            Assert.AreEqual<string>(Utility.CHILD_ONE_Name.ToString(NameFormat.FirstLastLong), childOne.DisplayName, String.Concat("Display Name should be Mr. Jim Doe: DisplayName is: <", childOne.DisplayName, ">"));
            Assert.AreEqual<Name>(Utility.CHILD_ONE_Name, childOne.Name, "Name should be 'Mr. Jim Doe'");
            Assert.AreEqual<Sex>(Utility.CHILD_ONE_Sex, childOne.Sex, "Sex should be Male");
            Assert.AreEqual(individual.Id, childOne.Father.Id, "Father should be 4");
            Assert.IsNull(childOne.Mother, "Mother should be null");

            //Child Two properties
            IIndividual childTwo = individual.Children[1];
            Assert.AreEqual<int>(Utility.CHILD_TWO_Id, childTwo.Id, "Child Two ID should be 6");
            Assert.AreEqual<DeathStatus>(Utility.CHILD_TWO_DeathStatus, childTwo.DeathStatus, "Death Status should be Living");
            Assert.AreEqual<string>(Utility.CHILD_TWO_Name.ToString(NameFormat.FirstLastLong), childTwo.DisplayName, String.Concat("Display Name should be an Ms. Jane Doe: DisplayName is: <", childTwo.DisplayName, ">"));
            Assert.AreEqual<Name>(Utility.CHILD_TWO_Name, childTwo.Name, "Name should be 'Ms. Jane Doe'");
            Assert.AreEqual<Sex>(Utility.CHILD_TWO_Sex, childTwo.Sex, "Sex should be Feale");
            Assert.AreEqual(individual.Id, childTwo.Father.Id, "Father should be 4");
            Assert.IsNull(childTwo.Mother, "Mother should be null");

            //Check other Child Collections are empty
            CheckIndividualChildCollections(individual, "Children");
        }

        [TestMethod]
        [Description("This test Gets an Individual that has a Spouse.")]
        [Owner("Charles Nurse")]
        public void GetIndividualWithSpouses()
        {
            IIndividual individual = FamilyTree.GetIndividual(Utility.INDIVIDUAL_SPOUSES_Id);

            //Object properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_SPOUSES_Id, individual.Id, "Set ID should be 7");
            CheckSetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            Assert.IsTrue(individual.Spouses.Count == 1, "Spouses Count should be 1");

            //Spouse properties
            IIndividual spouse = individual.Spouses[0];
            Assert.AreEqual<int>(Utility.SPOUSE_Id, spouse.Id, "Spouse ID should be 8");
            Assert.AreEqual<DeathStatus>(Utility.SPOUSE_DeathStatus, spouse.DeathStatus, "Death Status should be Living");
            Assert.AreEqual<string>(Utility.SPOUSE_Name.ToString(NameFormat.FirstLastLong), spouse.DisplayName, String.Concat("Display Name should be Mrs. Mary Smith: DisplayName is: <", spouse.DisplayName, ">"));
            Assert.AreEqual<Name>(Utility.SPOUSE_Name, spouse.Name, "Name should be 'Mrs. Mary Smith'");
            Assert.AreEqual<Sex>(Utility.SPOUSE_Sex, spouse.Sex, "Sex should be Female");
            Assert.AreEqual(individual.Id, spouse.Spouses[0].Id, "Spouse should be 7");
            CheckUnsetIndividualParents(individual);

            //Check other Child Collections are empty
            CheckIndividualChildCollections(individual, "Spouses");
        }

        [TestMethod]
        [Description("This test Gets an Individual that has Audit Info.")]
        [Owner("Charles Nurse")]
        public void GetIndividualWithAuditInfo()
        {
            IIndividual individual = FamilyTree.GetIndividual(Utility.INDIVIDUAL_AUDIT_Id);

            //Object properties
            Assert.AreEqual<int>(Utility.INDIVIDUAL_AUDIT_Id, individual.Id, "Set ID should be 9");
            CheckSetIndividualProperties(individual);
            CheckUnsetIndividualParents(individual);

            Assert.IsTrue(individual.Changed.Count == 2, "Changed Count should be 2");

            //Audit One properties
            IAuditInfo auditInfoOne = individual.Changed[0];
            Assert.AreEqual<int>(Utility.INDIVIDUAL_AUDITINFO_ONE_Id, auditInfoOne.Id, "Child One ID should be 10");
            Assert.AreEqual<DateTime>(Utility.INDIVIDUAL_AUDITINFO_ONE_Date, auditInfoOne.ChangeDate, "Changed Date should be: " + Utility.INDIVIDUAL_AUDITINFO_ONE_Date.ToString());
            Assert.AreEqual<string>(Utility.INDIVIDUAL_AUDITINFO_ONE_ChangedBy, auditInfoOne.ChangedBy, "Changed By should be 'John Smith'");
            Assert.AreEqual<string>(Utility.INDIVIDUAL_AUDITINFO_ONE_Description, auditInfoOne.Description, "Description should be 'Created this Individual'");
            Assert.AreEqual<AuditType>(Utility.INDIVIDUAL_AUDITINFO_ONE_Type, auditInfoOne.Type, "Type should be 'Created'");

            //Child Two properties
            IAuditInfo auditInfoTwo = individual.Changed[1];
            Assert.AreEqual<int>(Utility.INDIVIDUAL_AUDITINFO_TWO_Id, auditInfoTwo.Id, "AuditInfo Two ID should be 11");
            Assert.AreEqual<DateTime>(Utility.INDIVIDUAL_AUDITINFO_TWO_Date, auditInfoTwo.ChangeDate, "Changed Date should be: " + Utility.INDIVIDUAL_AUDITINFO_TWO_Date.ToString());
            Assert.AreEqual<string>(Utility.INDIVIDUAL_AUDITINFO_TWO_ChangedBy, auditInfoTwo.ChangedBy, "Changed By should be 'Jane Smith'");
            Assert.AreEqual<string>(Utility.INDIVIDUAL_AUDITINFO_TWO_Description, auditInfoTwo.Description, "Description should be 'Updated this Individual'");
            Assert.AreEqual<AuditType>(Utility.INDIVIDUAL_AUDITINFO_TWO_Type, auditInfoTwo.Type, "Type should be 'Updated'");

            //Check other Child Collections are empty
            CheckIndividualChildCollections(individual, "Changed");
        }

        #endregion
    }
}
